home *** CD-ROM | disk | FTP | other *** search
/ Programmer Power Tools / Programmer Power Tools.iso / editor / j414src.arc / IPROC.C < prev    next >
C/C++ Source or Header  |  1989-11-02  |  10KB  |  464 lines

  1. /***************************************************************************
  2.  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  3.  * is provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is    *
  5.  * included in all the files.                                              *
  6.  ***************************************************************************/
  7.  
  8. #include "jove.h"
  9. #include "re.h"
  10. #include "ctype.h"
  11. #include "disp.h"
  12. #if defined(IPROCS)
  13. # include "fp.h"
  14. # include "iproc.h"
  15. #endif
  16.  
  17. #ifdef    STDARGS
  18. # include <stdarg.h>
  19. #else
  20. # include <varargs.h>
  21. #endif
  22.  
  23. #ifdef IPROCS
  24.  
  25. private void
  26.     proc_rec proto ((Process *, char *)),
  27.     proc_close proto ((Process *)),
  28.     proc_kill proto((Process *, int)),
  29.     SendData proto ((int));
  30.  
  31. private SIGRESULT
  32.     proc_child proto((int));
  33.  
  34. #ifdef PIPEPROCS
  35. #   include "iproc-pipes.c"
  36. #else
  37. #   include "iproc-ptys.c"
  38. #endif
  39.  
  40. char    proc_prompt[128] = "% ";
  41.  
  42. char *
  43. pstate(p)
  44. Process    *p;
  45. {
  46.     switch (proc_state(p)) {
  47.     case NEW:
  48.         return "New";
  49.  
  50.     case STOPPED:
  51.         return "Stopped";
  52.  
  53.     case RUNNING:
  54.         return "Running";
  55.  
  56.     case DEAD:
  57.         if (p->p_howdied == EXITED) {
  58.             if (p->p_reason == 0)
  59.                 return "Done";
  60.             return sprint("Exit %d", p->p_reason);
  61.         }
  62.         return sprint("Killed %d", p->p_reason);
  63.  
  64.     default:
  65.         return "Unknown state";
  66.     }
  67. }
  68.  
  69. void
  70. KillProcs()
  71. {
  72.     register Process    *p;
  73.     register int    killem = -1;        /* -1 means undetermined */
  74.     register char    *yorn;
  75.  
  76.     for (p = procs; p != 0; p = p->p_next)
  77.         if (!isdead(p)) {
  78.             if (killem == -1) {
  79.                 yorn = ask("y", "Should I kill your i-processes? ");
  80.                 killem = (CharUpcase(*yorn) == 'Y');
  81.             }
  82.             if (killem)
  83.                 proc_kill(p, SIGKILL);
  84.         }
  85. }
  86.  
  87. void
  88. pbuftiedp(b)
  89. register Buffer    *b;
  90. {
  91.     register Process    *p = b->b_process;
  92.  
  93.     if (!isdead(p))
  94.         complain("Process %s, attached to %b, is %s.",
  95.              proc_cmd(p), b, pstate(p));
  96. }
  97.  
  98. char    dbx_parse_fmt[128] = "line \\([0-9]*\\) in \\{file,\\} *\"\\([^\"]*\\)\"";
  99.  
  100. void
  101. DBXpoutput()
  102. {
  103.     if (curbuf->b_process == 0)
  104.         complain("[Must be in a process buffer to enable dbx mode]");
  105.     curbuf->b_process->p_dbx_mode = !curbuf->b_process->p_dbx_mode;
  106.     UpdModLine = YES;
  107. }
  108.  
  109. private void
  110. watch_input(m)
  111. Mark    *m;
  112. {
  113.     Bufpos    save;
  114.     char    fname[FILESIZE],
  115.         lineno[FILESIZE];
  116.     int    lnum;
  117.     Window    *savew = curwind;
  118.     Buffer    *buf;
  119.  
  120.     DOTsave(&save);
  121.     ToMark(m);
  122.     if (dosearch(dbx_parse_fmt, FORWARD, YES) != NULL) {
  123.         get_FL_info(fname, lineno);
  124.         buf = do_find((Window *) 0, fname, YES);
  125.         pop_wind(buf->b_name, NO, -1);
  126.         lnum = atoi(lineno);
  127.         SetLine(next_line(buf->b_first, lnum - 1));
  128.         SetWind(savew);
  129.     }
  130.     SetDot(&save);
  131. }
  132.  
  133. /* Process receive: receives the characters in buf, and appends them to
  134.    the buffer associated with p. */
  135.  
  136. private void
  137. proc_rec(p, buf)
  138. register Process    *p;
  139. char    *buf;
  140. {
  141.     Buffer    *saveb = curbuf;
  142.     register Window    *w;
  143.     register Mark    *savepoint;
  144.     int    sameplace = NO,
  145.         do_disp = NO;
  146.  
  147.     if (curwind->w_bufp == p->p_buffer)
  148.         w = curwind;
  149.     else
  150.         w = windbp(p->p_buffer);    /* Is this window visible? */
  151.     if (w != 0)
  152.         do_disp = (in_window(w, p->p_mark->m_line) != -1);
  153.     SetBuf(p->p_buffer);
  154.     savepoint = MakeMark(curline, curchar, M_FLOATER);
  155.     ToMark(p->p_mark);        /* where output last stopped */
  156.     if (savepoint->m_line == curline && savepoint->m_char == curchar)
  157.         sameplace = YES;
  158.     ins_str(buf, YES);
  159.     if (do_disp == YES && p->p_dbx_mode == YES)
  160.         watch_input(p->p_mark);
  161.     MarkSet(p->p_mark, curline, curchar);
  162.     if (!sameplace)
  163.         ToMark(savepoint);    /* back to where we were */
  164.     DelMark(savepoint);
  165.     /* redisplay now, instead of right after the ins_str, so that
  166.        we don't get a bouncing effect if point is not the same as
  167.        the process output position */
  168.     if (do_disp) {
  169.         w->w_line = curline;
  170.         w->w_char = curchar;
  171.         redisplay();
  172.     }
  173.     SetBuf(saveb);
  174. }
  175.  
  176. private void
  177. proc_kill(p, sig)
  178. register Process    *p;
  179. int    sig;
  180. {
  181.     if (isdead(p))
  182.         return;
  183.     if (killpg(p->p_pid, sig) == -1)
  184.         s_mess("Cannot kill %s!", proc_buf(p));
  185. }
  186.  
  187. /* Free process CHILD.  Do all the necessary cleaning up (closing fd's,
  188.    etc.). */
  189.  
  190. private void
  191. free_proc(child)
  192. Process    *child;
  193. {
  194.     register Process    *p,
  195.                 *prev = 0;
  196.  
  197.     if (!isdead(child))
  198.         return;
  199.     for (p = procs; p != child; prev = p, p = p->p_next)
  200.         ;
  201.     if (prev == 0)
  202.         procs = child->p_next;
  203.     else
  204.         prev->p_next = child->p_next;
  205.     proc_close(child);        /* if not already closed */
  206.  
  207.     /* It's possible that the buffer has been given another process
  208.        between the time CHILD dies and CHILD's death is noticed (via
  209.        list-processes).  So we only set it the buffer's process to
  210.        0 if CHILD is still the controlling process. */
  211.     if (child->p_buffer->b_process == child) {
  212.         child->p_buffer->b_process = 0;
  213.     }
  214.     {
  215.         Buffer    *old = curbuf;
  216.  
  217.         SetBuf(child->p_buffer);
  218.         DelMark(child->p_mark);
  219.         SetBuf(old);
  220.     }
  221.     free((char *) child->p_name);
  222.     free((char *) child);
  223. }
  224.  
  225. void
  226. ProcList()
  227. {
  228.     register Process    *p,
  229.                 *next;
  230.     char    *fmt = "%-15s  %-15s  %-8s %s",
  231.         pidstr[16];
  232.  
  233.     if (procs == 0) {
  234.         message("[No subprocesses]");
  235.         return;
  236.     }
  237.     TOstart("Process list", TRUE);
  238.  
  239.     Typeout(fmt, "Buffer", "Status", "Pid ", "Command");
  240.     Typeout(fmt, "------", "------", "--- ", "-------");
  241.     for (p = procs; p != 0; p = next) {
  242.         next = p->p_next;
  243.         swritef(pidstr, "%d", p->p_pid);
  244.         Typeout(fmt, proc_buf(p), pstate(p), pidstr, p->p_name);
  245.         if (isdead(p)) {
  246.             free_proc(p);
  247.             UpdModLine = YES;
  248.         }
  249.     }
  250.     TOstop();
  251. }
  252.  
  253. private void
  254. do_rtp(mp)
  255. register Mark    *mp;
  256. {
  257.     register Process    *p = curbuf->b_process;
  258.     Line    *line1 = curline,
  259.         *line2 = mp->m_line;
  260.     int    char1 = curchar,
  261.         char2 = mp->m_char;
  262.     char    *gp;
  263.     size_t    nbytes;
  264.  
  265.     if (isdead(p) || p->p_buffer != curbuf)
  266.         return;
  267.  
  268.     (void) fixorder(&line1, &char1, &line2, &char2);
  269.     while (line1 != line2->l_next) {
  270.         gp = ltobuf(line1, genbuf) + char1;
  271.         if (line1 == line2)
  272.             gp[char2] = '\0';
  273.         else
  274.             strcat(gp, "\n");
  275.         if ((nbytes = strlen(gp)) != 0)
  276.             proc_write(p, gp, nbytes);
  277.         line1 = line1->l_next;
  278.         char1 = 0;
  279.     }
  280. }
  281.  
  282. void
  283. ProcNewline()
  284. {
  285. #ifdef ABBREV
  286.     MaybeAbbrevExpand();
  287. #endif
  288.     SendData(YES);
  289. }
  290.  
  291. void
  292. ProcSendData()
  293. {
  294. #ifdef ABBREV
  295.     MaybeAbbrevExpand();
  296. #endif
  297.     SendData(NO);
  298. }
  299.  
  300. private void
  301. SendData(newlinep)
  302. int    newlinep;
  303. {
  304.     register Process    *p = curbuf->b_process;
  305.     register char    *lp,
  306.             *gp;    /* JF fix for better prompt handling */
  307.  
  308.     if (isdead(p))
  309.         return;
  310.     /* If the process mark was involved in a big deletion, because
  311.        the user hit ^W or something, then let's do some magic with
  312.        the process mark.  Problem is that if the user yanks back the
  313.        text he deleted, the mark stays at the beginning of the region,
  314.        and so the next time SendData() is called the entire region
  315.        will be sent.  That's not good.  So, to deal with that we reset
  316.        the mark to the last line, after skipping over the prompt, etc. */
  317.     if (p->p_mark->m_flags & M_BIG_DELETE) {
  318.         Bufpos    bp;
  319.  
  320.         p->p_mark->m_flags &= ~M_BIG_DELETE;
  321.  
  322.         DOTsave(&bp);
  323.         ToLast();
  324.         Bol();
  325.         /* While we're looking at a prompt, and while we're
  326.            moving forward.  This is for people who accidently
  327.            set their process-prompt to ">*" which will always
  328.            match! */
  329.         while ((LookingAt(proc_prompt, linebuf, curchar)) &&
  330.                (REeom > curchar))
  331.             curchar = REeom;
  332.         MarkSet(p->p_mark, curline, curchar);
  333.         SetDot(&bp);
  334.     }
  335.  
  336.     if (lastp(curline)) {
  337.         Eol();
  338.         if (newlinep)
  339.             LineInsert(1);
  340.         do_rtp(p->p_mark);
  341.         MarkSet(p->p_mark, curline, curchar);
  342.     } else {
  343.         /* Either we're looking at a prompt, or we're not, in
  344.            which case we want to strip off the beginning of the
  345.            line anything that looks like what the prompt at the
  346.            end of the file is.  In other words, if "(dbx) stop in
  347.            ProcessNewline" is the line we're on, and the last
  348.            line in the buffer is "(dbx) ", then we strip off the
  349.            leading "(dbx) " from this line, because we know it's
  350.            part of the prompt.  But this only happens if "(dbx) "
  351.            isn't one of the process prompts ... follow what I'm
  352.            saying? */
  353.         Bol();
  354.         if (LookingAt(proc_prompt, linebuf, curchar)) {
  355.             do
  356.                 curchar = REeom;
  357.             while ((LookingAt(proc_prompt, linebuf, curchar)) &&
  358.                    (REeom > curchar));
  359.             strcpy(genbuf, linebuf + curchar);
  360.             Eof();
  361.             ins_str(genbuf, NO);
  362.         } else {
  363.             strcpy(genbuf, linebuf + curchar);
  364.             Eof();
  365.             gp = genbuf;
  366.             lp = linebuf;
  367.             while (*lp == *gp && *lp != '\0') {
  368.                 lp += 1;
  369.                 gp += 1;
  370.             }
  371.             ins_str(gp, NO);
  372.         }
  373.     }
  374. }
  375.  
  376. void
  377. ShellProc()
  378. {
  379.     char    *shbuf = "*shell*";
  380.     register Buffer    *b;
  381.  
  382.     b = buf_exists(shbuf);
  383.     if (b == 0 || isdead(b->b_process))
  384.         proc_strt(shbuf, NO, Shell, "-i", (char *) 0);
  385.     pop_wind(shbuf, NO, -1);
  386. }
  387.  
  388. void
  389. Iprocess()
  390. {
  391.     register char    *command;
  392.     char    scratch[64],
  393.         *bnm;
  394.     int    cnt = 1;
  395.     Buffer    *bp;
  396.  
  397.     command = ask(ShcomBuf, ProcFmt);
  398.     null_ncpy(ShcomBuf, command, (sizeof ShcomBuf) - 1);
  399.     bnm = MakeName(command);
  400.     strcpy(scratch, bnm);
  401.     while ((bp = buf_exists(scratch)) != NIL && !isdead(bp->b_process))
  402.         swritef(scratch, "%s.%d", bnm, cnt++);
  403.     proc_strt(scratch, YES, Shell, ShFlags, command, (char *) 0);
  404. }
  405.  
  406. private SIGRESULT
  407. proc_child(junk)
  408. int    junk;    /* needed for signal handler; not used */
  409. {
  410.     union wait    w;
  411.     register int    pid;
  412.  
  413.     for (;;) {
  414. #ifndef WAIT3
  415.         pid = wait2(&w.w_status, (WNOHANG | WUNTRACED));
  416. #else
  417.         pid = wait3(&w, (WNOHANG | WUNTRACED), (struct rusage *) 0);
  418. #endif
  419.         if (pid <= 0)
  420.             break;
  421.         kill_off(pid, w);
  422.     }
  423.     SIGRETURN;
  424. }
  425.  
  426. void
  427. kill_off(pid, w)
  428. register int    pid;
  429. union wait    w;
  430. {
  431.     register Process    *child;
  432.  
  433.     if ((child = proc_pid(pid)) == 0)
  434.         return;
  435.  
  436.     UpdModLine = YES;        /* we're changing state ... */
  437.     if (WIFSTOPPED(w))
  438.         child->p_state = STOPPED;
  439.     else {
  440.         child->p_state = DEAD;
  441.         if (WIFEXITED(w))
  442.             child->p_howdied = EXITED;
  443.         else if (WIFSIGNALED(w)) {
  444.             child->p_reason = w_termsignum(w);
  445.             child->p_howdied = KILLED;
  446.         }
  447.         {
  448.             Buffer    *save = curbuf;
  449.             char    mesg[128];
  450.  
  451.             /* insert status message now */
  452.             swritef(mesg, "[Process %s: %s]\n",
  453.                 proc_cmd(child),
  454.                 pstate(child));
  455.             SetBuf(child->p_buffer);
  456.             ins_str(mesg, NO);
  457.             SetBuf(save);
  458.             redisplay();
  459.         }
  460.     }
  461. }
  462.  
  463. #endif /* IPROCS */
  464.